/**
 * 
 */
package stv5;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Map.Entry;

/**
 * This represents an HTTP request from some client
 * 
 * @author Daniel
 *
 */
public class Request implements Iterable<Entry<String,String>> {
	public enum Target {
		MEDIA,
		SETTINGS,
		INDEX,
		FILES
	}
	public enum Type {
		BROWSE,
		VIEW,
		SAVE,
		OTHER
	}
	
	private Request.Target target;
	private Request.Type type;
	private HashMap<String, String> vars;
	private String rawUrl;
	private boolean isLocal = false;
	
	private Request(Request.Target target, Request.Type type, 
			HashMap<String, String> vars, String raw) {
		this.target = target;
		this.type = type;
		this.vars = vars;
		this.rawUrl = raw;
	}
	
	public Request.Target getTarget() {
		return target;
	}
	
	public Request.Type getType() {
		return type;
	}
	
	public String getRaw() {
		return rawUrl;
	}
	
	public String getVar(String name) {
		return vars.get(name);
	}
	
	public Set< Entry<String, String> > getVars() {
		return vars.entrySet();
	}		
	
	public boolean hasVar(String name) {
		return vars.containsKey(name);
	}
	
	/**
	 * @return True if the request came from the local
	 * 	machine, otherwise False
	 */
	public boolean isLocal() {
		return isLocal;
	}
	
	/**
	 * @see #isLocal()
	 */
	public void setLocal(boolean isLocal) {
		this.isLocal = isLocal;
	}
	
	public int size() {
		return vars.size();
	}
	
	public Iterator<Entry<String,String>> iterator() {
		return vars.entrySet().iterator();
	}		
	
	/**
	 * Requests should be in the following format:
	 *		/TARGET/REQUEST_TYPE/?var=val&var=val&...
	 *	Where TARGET could be "media", "settings", or "index"
	 *  and REQUEST_TYPE could be "browse" or "view" for
	 *  	media, and "save" or "view" for settings. It will
	 *  	be "other" for "index"
	 *   
	 * I'm going to be pretty lazy and only use GET requests
	 *   for everything, at least for now 
	 * @param head
	 * @return
	 */
	public static Request parse(String head, String body) {
		//System.out.println("* Parsing: " + head);
		Request.Target tgt = Target.INDEX;
		Request.Type type = Type.OTHER;		
		HashMap<String, String> vars = new HashMap<String, String>();
		
		String[] tmp = head.split(" ");
		String msgType = tmp[0];
		if (!("GET".equals(msgType) || "POST".equals(msgType)))
			return null;
		String rawUrl = tmp[1];
		String[] input = tmp[1].split("/");
		
		// if it's two or less, it should just be index
		if (input.length > 2) {
			// figure out the target
			if ("media".equals(input[1].toLowerCase())) {
				tgt = Target.MEDIA;
			} 
			else if ("settings".equals(input[1].toLowerCase())) {
				tgt = Target.SETTINGS;
			}
			int filePos = rawUrl.toLowerCase().indexOf("files");
			if (filePos > -1) {
				tgt = Target.FILES;
				// take "files" out of the url
				rawUrl = rawUrl.substring(filePos + 5);
			}
			
			// figure out the type;
			if ("browse".equals(input[2].toLowerCase())) {
				type = Type.BROWSE;
			}
			else if ("view".equals(input[2].toLowerCase())) {
				type = Type.VIEW;
			}
			else if ("save".equals(input[2].toLowerCase())) {
				type = Type.SAVE;
			} 
			
			// parse variables
			if (input.length > 3 && input[3].length() > 2) {
				extractVars(vars, input[3].substring(1));
			}
						
			// if it's a POST, read the body for variables, too
			if ("POST".equals(msgType)) {
				extractVars(vars, body);
			}
		}
		
		return new Request(tgt, type, vars, rawUrl);
	}

	/**
	 * Extract vars from input and put them into hashmap "vars"
	 * @param vars
	 * @param input
	 */
	private static void extractVars(HashMap<String, String> vars, String input) {
		String[] tmp;
		String[] rawVars = input.split("&");
		for (String raw : rawVars) {
			tmp = raw.split("=");
			if (tmp != null && tmp.length == 2) {
				vars.put(tmp[0], tmp[1]);
			}
		}
	}

	
}